import { NativeModules, NativeEventEmitter } from 'react-native';
import MD5 from 'react-native-md5';

import { isIOS } from '../../../constant';
import { CoinApi } from '../../../api';
import { InPayErrCode } from './constant';
import Log from '../../../common/log';
import { IAPCommodityInfo } from '../../../api/coin/getIAPCommodityList';
import { pointToYuan } from '../../transformMoney';

const TAG = 'inAppPurchaseModule';

let resCallBack: ((value: Error) => void) | null;
let timer: NodeJS.Timer | null;
let localUserId: string;
let commodities: IAPCommodityInfo[] = [
  {
    name: '1蜜蜂币',
    price: 100,
    commodityId: 'yutoucoin_1',
    yutouCoinNum: 100
  },
  {
    name: '8蜜蜂币',
    price: 1200,
    commodityId: 'yutoucoin_2',
    yutouCoinNum: 1200
  },
  {
    name: '21蜜蜂币',
    price: 3000,
    commodityId: 'yutoucoin_3',
    yutouCoinNum: 3000
  },
  {
    name: '35蜜蜂币',
    price: 5000,
    commodityId: 'yutoucoin_4',
    yutouCoinNum: 5000
  },
  {
    name: '75蜜蜂币',
    price: 10800,
    commodityId: 'yutoucoin_5',
    yutouCoinNum: 10800
  },
  {
    name: '145蜜蜂币',
    price: 20800,
    commodityId: 'yutoucoin_6',
    yutouCoinNum: 20800
  },
  {
    name: '215蜜蜂币',
    price: 30800,
    commodityId: 'yutoucoin_7',
    yutouCoinNum: 30800
  },
  {
    name: '292蜜蜂币',
    price: 41800,
    commodityId: 'yutoucoin_8',
    yutouCoinNum: 41800
  },
  {
    name: '362蜜蜂币',
    price: 51800,
    commodityId: 'yutoucoin_9',
    yutouCoinNum: 51800
  }
];

const { RNInAppPurchaseModule } = NativeModules;
const NativeModule = new NativeEventEmitter(RNInAppPurchaseModule);

interface CreateOrder {
  productIdentifier: string;
  md5: string;
  price: string;
  transactionId: string;
}

interface SendCertificate {
  receipts: string;
  md5: string;
  orderId: string;
  transactionId: string;
}

export interface Error {
  msg: string;
  code: InPayErrCode;
  nativeCode: number;
}

// 用户是否禁止应用内付费购买
const canMakePayments = (): boolean =>
  isIOS && NativeModules.InAppPurchaseModule.canMakePayments();

/**
 * 当前手机是否翻墙
 * 如果手机翻墙禁止发起支付
 */
const currentDeviceIsJailbroken = (): boolean =>
  isIOS && NativeModules.InAppPurchaseModule.currentDeviceIsJailbroken();

/**
 * 是否所有的待验证任务都完成了
 * 1.退出前的警告信息(比如用户有尚未得到验证的订单)
 * 2.重新创建订单的时候需要检查一下，如果存在则继续该订单的验证，否则开启新订单
 */
const didNeedVerifyQueueClearedForCurrentUser = (): boolean =>
  isIOS &&
  NativeModules.InAppPurchaseModule.didNeedVerifyQueueClearedForCurrentUser();

/**
 * 注销当前支付管理者
 * 在用户退出登录时调用
 */
const logoutPaymentManager = (): void => {
  if (!isIOS) return;
  if (timer) {
    clearTimeout(timer);
    timer = null;
  }
  NativeModules.InAppPurchaseModule.logoutPaymentManager();
};

/**
 * 清除交易数据
 */
const clearKeyChain = (): void => {
  if (!isIOS) return;
  NativeModules.InAppPurchaseModule.clearKeyChain();
};

/**
 * 开始一个新订单验证
 * 如果当前存在待验证的订单，则调用该方法继续验证
 */
const startNextTaskIfNeed = (): void => {
  if (!isIOS) return;
  NativeModules.InAppPurchaseModule.startNextTaskIfNeed();
};

/**
 * 开始支付事务监听, 并且开始支付凭证验证队列
 * 请在用户登录时和用户重新启动 APP 时调用
 */
const startTransactionObservingAndPaymentTransactionVerifingWithUserID = (
  userId: string
): void => {
  if (!isIOS) return;
  if (timer) {
    clearTimeout(timer);
    timer = null;
  }
  localUserId = `${userId}`;
  timer = setTimeout((): void => {
    NativeModules.InAppPurchaseModule.startTransactionObservingAndPaymentTransactionVerifingWithUserID(
      localUserId
    );
  }, 5000);
};

/**
 * 获取产品信息
 * 点击商品后，先获取商品信息，再购买
 */
const fetchProductInfoWithProductIdentifiers = (
  id: string,
  callback: any
): void => {
  if (!isIOS) return;
  NativeModules.InAppPurchaseModule.fetchProductInfoWithProductIdentifiers(
    id,
    callback
  );
};

/**
 * 购买某个产品
 */
const buyProduct = (product: any): void => {
  if (!isIOS) return;
  NativeModules.InAppPurchaseModule.buyProduct(product);
};

/**
 * 订单验证成功
 */
const handleVerifingTransactionValid = (): void => {
  if (!isIOS) return;
  NativeModules.InAppPurchaseModule.handleVerifingTransactionValid();
};

/**
 * 1.订单验证成功
 * 2:客服已发货，服务器认为这个订单已经验证成功
 */
const handleVerifingTransactionInvalidWithErrorMessage = (): void => {
  if (!isIOS) return;
  NativeModules.InAppPurchaseModule.handleVerifingTransactionInvalidWithErrorMessage();
};

/**
 * 订单验证失败
 */
const handleUploadCertificateRequestFailed = (): void => {
  if (!isIOS) return;
  NativeModules.InAppPurchaseModule.handleUploadCertificateRequestFailed();
};

/**
 * 创建订单成功
 */
const handleCreateOrderSuccessedWithOrderNo = (
  orderNo: string,
  priceTagString: string,
  md5: string
): void => {
  if (!isIOS) return;
  NativeModules.InAppPurchaseModule.handleCreateOrderSuccessedWithOrderNo(
    orderNo,
    priceTagString,
    md5
  );
};

/**
 * 创建订单失败
 */
const handleCreateOrderFailed = (): void => {
  if (!isIOS) return;
  NativeModules.InAppPurchaseModule.handleCreateOrderFailed();
};

const addEventEmitter = (): void => {
  if (!isIOS) return;

  const report = (resp: any): void => {
    Log.i(TAG, JSON.stringify({ event: 'pay res', resp }));
  };

  // 创建订单
  NativeModule.addListener('CREATE_ORDER', (resp: CreateOrder): void => {
    const { productIdentifier, transactionId } = resp;
    const currentCommodity = commodities.find(
      (commodity): boolean => commodity.commodityId === productIdentifier
    );

    if (!currentCommodity) return;

    const { price } = currentCommodity;

    const params = {
      iapCommodityId: productIdentifier,
      payMethod: 5,
      price,
      userPayAmount: price,
      md5: MD5.hex_md5(
        JSON.stringify({
          userId: localUserId,
          iapProductId: productIdentifier,
          transactionId
        })
      )
    };
    CoinApi.IAPBuyYutouCoin(params)
      .then((res): void => {
        if (res.code === 0) {
          const {
            orderId,
            md5: orderMd5,
            userPayAmount: orderPrice
          } = res.data;
          handleCreateOrderSuccessedWithOrderNo(
            `${orderId}`,
            `${pointToYuan(orderPrice)}`,
            orderMd5
          );
        } else {
          // handleCreateOrderFailed();
          const resData = {
            code: InPayErrCode.InPayCreateOrderFail,
            msg: '创建订单失败',
            nativeCode: InPayErrCode.InPayUnknown
          };
          if (resCallBack) {
            resCallBack(resData);
          }
          report(resData);
        }
      })
      .catch((): void => {
        // handleCreateOrderFailed();
        const resData = {
          code: InPayErrCode.InPayCreateOrderFail,
          msg: '创建订单失败',
          nativeCode: InPayErrCode.InPayUnknown
        };
        if (resCallBack) {
          resCallBack(resData);
        }
        report(resData);
      });
  });

  // 发送验证
  NativeModule.addListener(
    'SEND_UPLOAD_CERTIFICATE_REQUEST',
    (resp: SendCertificate): void => {
      const { receipts, orderId, transactionId } = resp;
      const params = {
        orderId,
        iapTransactionId: transactionId,
        iapReceipt: receipts
      };
      CoinApi.getIAPBuyYutouCoinPayResult(params)
        .then((res): void => {
          if (res.code === 0) {
            const { orderStatus } = res.data;
            if (orderStatus === 2) {
              // 支付成功
              handleVerifingTransactionValid();
              if (resCallBack) {
                resCallBack({
                  code: InPayErrCode.InPayCheckOrderSuccess,
                  msg: orderId,
                  nativeCode: InPayErrCode.InPayUnknown
                });
              }
            }
          } else {
            handleUploadCertificateRequestFailed();
            const resData = {
              code: InPayErrCode.InPayCheckOrderFail,
              msg: '支付失败',
              nativeCode: InPayErrCode.InPayUnknown
            };
            if (resCallBack) {
              resCallBack(resData);
            }
            report(resData);
          }
        })
        .catch((): void => {
          handleUploadCertificateRequestFailed();
          const resData = {
            code: InPayErrCode.InPayCheckOrderFail,
            msg: '支付失败',
            nativeCode: InPayErrCode.InPayUnknown
          };
          if (resCallBack) {
            resCallBack(resData);
          }
          report(resData);
        });
    }
  );

  // 内购错误收集
  NativeModule.addListener('IN_APP_PURCHASE_ERROR', (resp: Error): void => {
    const errorReport = (): void => {
      Log.i(TAG, JSON.stringify({ event: 'pay err', resp }));
    };
    const callbackRes = (): void => {
      if (resCallBack) {
        resCallBack(resp);
      }
    };
    switch (resp.code) {
      case InPayErrCode.InPaySuccess:
        break;
      case InPayErrCode.InPayNoProduct:
      case InPayErrCode.InPayBuyFail:
      case InPayErrCode.InPayBuyCancel:
      case InPayErrCode.InPayHaveBuy:
      case InPayErrCode.InPayTransactionDelay:
      case InPayErrCode.InPayTransaction:
      case InPayErrCode.InPayTransactionSuccess:
        callbackRes();
        break;
      case InPayErrCode.InPayNoReceipt:
      case InPayErrCode.InPayTransactionSuccessNoReceipt:
        callbackRes();
        errorReport();
        break;
      case InPayErrCode.InPayTransactionError:
      case InPayErrCode.InPayInitModalError:
      case InPayErrCode.InPayMaxVerifyTime:
      case InPayErrCode.InPayTransactionError1:
        errorReport();
        break;
      default:
        break;
    }
  });
};

const removeEventEmitter = (): void => {
  if (!isIOS) return;

  if (timer) {
    clearTimeout(timer);
    timer = null;
  }
  NativeModule.removeAllListeners();
};

const startBuy = (id: string, callback: (value: Error) => void): void => {
  resCallBack = callback;
  if (!didNeedVerifyQueueClearedForCurrentUser()) {
    startNextTaskIfNeed();
    return;
  }

  fetchProductInfoWithProductIdentifiers(id, (res: string): void => {
    // 有回调，说明商品有异常，没有回调说明请求到商品信息后，直接进行购买
    Log.i(TAG, JSON.stringify({ event: 'product err', res }));
  });
};

const cancelBuy = (): void => {
  resCallBack = null;
};

const initCommodities = (c: IAPCommodityInfo[]): void => {
  commodities = c;
};

export default {
  canMakePayments,
  didNeedVerifyQueueClearedForCurrentUser,
  currentDeviceIsJailbroken,
  logoutPaymentManager,
  startNextTaskIfNeed,
  startTransactionObservingAndPaymentTransactionVerifingWithUserID,
  fetchProductInfoWithProductIdentifiers,
  buyProduct,
  handleVerifingTransactionValid,
  handleVerifingTransactionInvalidWithErrorMessage,
  handleUploadCertificateRequestFailed,
  handleCreateOrderSuccessedWithOrderNo,
  handleCreateOrderFailed,
  addEventEmitter,
  removeEventEmitter,
  startBuy,
  cancelBuy,
  clearKeyChain,
  initCommodities
};
